package com.school.sports.controller;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.school.sports.entity.OperationLog;
import com.school.sports.service.OperationLogService;
import com.school.sports.common.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.format.annotation.DateTimeFormat;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 操作日志控制器
 * 提供操作日志的查询、统计、导出、清理等功能
 */
@RestController
@RequestMapping("/api/operation-logs")
public class OperationLogController {

    private static final Logger logger = LoggerFactory.getLogger(OperationLogController.class);

    @Autowired
    private OperationLogService operationLogService;

    /**
     * 分页查询操作日志
     * @param currentPage 当前页码
     * @param pageSize 每页大小
     * @param operationLog 查询条件
     * @return 分页结果
     */
    @GetMapping("/page/{currentPage}/{pageSize}")
    @PreAuthorize("hasRole('管理员')")
    public Result<IPage<OperationLog>> getOperationLogPage(
            @PathVariable("currentPage") Integer currentPage,
            @PathVariable("pageSize") Integer pageSize,
            OperationLog operationLog) {

        logger.info("分页查询操作日志，当前页码：{}，每页条数：{}，查询条件：{}", currentPage, pageSize, operationLog);

        // 参数校验
        if (currentPage == null || currentPage <= 0) {
            currentPage = 1;
        }
        if (pageSize == null || pageSize <= 0) {
            pageSize = 10;
        }

        try {
            IPage<OperationLog> page = operationLogService.getOperationLogPage(currentPage, pageSize, operationLog);
            logger.info("查询操作日志成功，共{}条记录", page.getTotal());
            return Result.success(page);
        } catch (Exception e) {
            logger.error("查询操作日志异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 根据用户ID查询操作日志
     * @param userId 用户ID
     * @param limit 查询条数限制
     * @return 操作日志列表
     */
    @GetMapping("/by-user/{userId}")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<List<OperationLog>> getOperationLogsByUserId(
            @PathVariable("userId") Long userId,
            @RequestParam(value = "limit", required = false) Integer limit) {

        logger.info("根据用户ID查询操作日志，用户ID：{}，限制条数：{}", userId, limit);

        if (userId == null || userId <= 0) {
            return Result.fail("用户ID无效");
        }

        try {
            List<OperationLog> logs = operationLogService.getOperationLogsByUserId(userId, limit);
            logger.info("查询成功，共{}条记录", logs.size());
            return Result.success(logs);
        } catch (Exception e) {
            logger.error("根据用户ID查询操作日志异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 根据操作类型查询操作日志
     * @param operationType 操作类型
     * @param limit 查询条数限制
     * @return 操作日志列表
     */
    @GetMapping("/by-type/{operationType}")
    @PreAuthorize("hasRole('管理员')")
    public Result<List<OperationLog>> getOperationLogsByType(
            @PathVariable("operationType") String operationType,
            @RequestParam(value = "limit", required = false) Integer limit) {

        logger.info("根据操作类型查询操作日志，操作类型：{}，限制条数：{}", operationType, limit);

        try {
            List<OperationLog> logs = operationLogService.getOperationLogsByType(operationType, limit);
            logger.info("查询成功，共{}条记录", logs.size());
            return Result.success(logs);
        } catch (Exception e) {
            logger.error("根据操作类型查询操作日志异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 根据时间范围查询操作日志
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 操作日志列表
     */
    @GetMapping("/by-time-range")
    @PreAuthorize("hasRole('管理员')")
    public Result<List<OperationLog>> getOperationLogsByTimeRange(
            @RequestParam(value = "startTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
            @RequestParam(value = "endTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {

        logger.info("根据时间范围查询操作日志，开始时间：{}，结束时间：{}", startTime, endTime);

        try {
            List<OperationLog> logs = operationLogService.getOperationLogsByTimeRange(startTime, endTime);
            logger.info("查询成功，共{}条记录", logs.size());
            return Result.success(logs);
        } catch (Exception e) {
            logger.error("根据时间范围查询操作日志异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 统计各类型操作日志数量
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 统计结果
     */
    @GetMapping("/statistics/by-type")
    @PreAuthorize("hasRole('管理员')")
    public Result<Map<String, Long>> countByOperationType(
            @RequestParam(value = "startTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
            @RequestParam(value = "endTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {

        logger.info("统计各类型操作日志数量，开始时间：{}，结束时间：{}", startTime, endTime);

        try {
            Map<String, Long> statistics = operationLogService.countByOperationType(startTime, endTime);
            logger.info("统计完成，共{}种操作类型", statistics.size());
            return Result.success(statistics);
        } catch (Exception e) {
            logger.error("统计操作类型异常：{}", e.getMessage(), e);
            return Result.fail("统计失败：" + e.getMessage());
        }
    }

    /**
     * 统计用户操作次数
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @param topN 统计前N名
     * @return 统计结果
     */
    @GetMapping("/statistics/by-user")
    @PreAuthorize("hasRole('管理员')")
    public Result<List<Map<String, Object>>> countByUserId(
            @RequestParam(value = "startTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
            @RequestParam(value = "endTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime,
            @RequestParam(value = "topN", defaultValue = "10") Integer topN) {

        logger.info("统计用户操作次数，开始时间：{}，结束时间：{}，前N名：{}", startTime, endTime, topN);

        try {
            List<Map<String, Object>> statistics = operationLogService.countByUserId(startTime, endTime, topN);
            logger.info("统计完成，共{}个用户", statistics.size());
            return Result.success(statistics);
        } catch (Exception e) {
            logger.error("统计用户操作次数异常：{}", e.getMessage(), e);
            return Result.fail("统计失败：" + e.getMessage());
        }
    }

    /**
     * 统计每日操作数量
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 统计结果
     */
    @GetMapping("/statistics/by-date")
    @PreAuthorize("hasRole('管理员')")
    public Result<List<Map<String, Object>>> countByDate(
            @RequestParam(value = "startTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
            @RequestParam(value = "endTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {

        logger.info("统计每日操作数量，开始时间：{}，结束时间：{}", startTime, endTime);

        try {
            List<Map<String, Object>> statistics = operationLogService.countByDate(startTime, endTime);
            logger.info("统计完成，共{}天", statistics.size());
            return Result.success(statistics);
        } catch (Exception e) {
            logger.error("统计每日操作数量异常：{}", e.getMessage(), e);
            return Result.fail("统计失败：" + e.getMessage());
        }
    }

    /**
     * 统计失败操作数量
     * @param startTime 开始时间
     * @param endTime 结束时间
     * @return 统计结果
     */
    @GetMapping("/statistics/failed")
    @PreAuthorize("hasRole('管理员')")
    public Result<Long> countFailedOperations(
            @RequestParam(value = "startTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime startTime,
            @RequestParam(value = "endTime", required = false) @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime endTime) {

        logger.info("统计失败操作数量，开始时间：{}，结束时间：{}", startTime, endTime);

        try {
            Long count = operationLogService.countFailedOperations(startTime, endTime);
            logger.info("统计完成，失败操作数量：{}", count);
            return Result.success(count);
        } catch (Exception e) {
            logger.error("统计失败操作数量异常：{}", e.getMessage(), e);
            return Result.fail("统计失败：" + e.getMessage());
        }
    }

    /**
     * 导出操作日志到Excel
     * @param operationLog 查询条件
     * @param response HTTP响应对象
     */
    @GetMapping("/export")
    @PreAuthorize("hasRole('管理员')")
    public void exportOperationLogs(OperationLog operationLog, HttpServletResponse response) {
        logger.info("导出操作日志，查询条件：{}", operationLog);

        try {
            operationLogService.exportOperationLogs(operationLog, response);
            logger.info("导出操作日志成功");
        } catch (Exception e) {
            logger.error("导出操作日志异常：{}", e.getMessage(), e);
            throw new RuntimeException("导出失败：" + e.getMessage());
        }
    }

    /**
     * 批量删除操作日志
     * @param ids 日志ID列表
     * @return 操作结果
     */
    @DeleteMapping("/batch")
    @PreAuthorize("hasRole('管理员')")
    public Result<String> batchDeleteLogs(@RequestBody List<Long> ids) {
        logger.info("批量删除操作日志，ID列表：{}", ids);

        if (ids == null || ids.isEmpty()) {
            return Result.fail("请选择要删除的日志");
        }

        try {
            boolean success = operationLogService.batchDeleteLogs(ids);
            if (success) {
                logger.info("批量删除操作日志成功，共{}条记录", ids.size());
                return Result.success("批量删除成功");
            } else {
                return Result.fail("批量删除失败");
            }
        } catch (Exception e) {
            logger.error("批量删除操作日志异常：{}", e.getMessage(), e);
            return Result.fail("批量删除失败：" + e.getMessage());
        }
    }

    /**
     * 清理指定时间之前的日志
     * @param beforeTime 时间点
     * @return 清理数量
     */
    @DeleteMapping("/clean-before")
    @PreAuthorize("hasRole('管理员')")
    public Result<String> cleanLogsBeforeTime(
            @RequestParam("beforeTime") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") LocalDateTime beforeTime) {

        logger.info("清理指定时间之前的日志，时间点：{}", beforeTime);

        if (beforeTime == null) {
            return Result.fail("时间参数无效");
        }

        try {
            Integer count = operationLogService.cleanLogsBeforeTime(beforeTime);
            logger.info("清理操作日志成功，共{}条记录", count);
            return Result.success("清理成功，共删除" + count + "条记录");
        } catch (Exception e) {
            logger.error("清理操作日志异常：{}", e.getMessage(), e);
            return Result.fail("清理失败：" + e.getMessage());
        }
    }

    /**
     * 获取最近的操作日志
     * @param limit 查询条数
     * @return 操作日志列表
     */
    @GetMapping("/recent")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<List<OperationLog>> getRecentOperationLogs(
            @RequestParam(value = "limit", defaultValue = "10") Integer limit) {

        logger.info("获取最近的操作日志，限制条数：{}", limit);

        try {
            List<OperationLog> logs = operationLogService.getRecentOperationLogs(limit);
            logger.info("查询成功，共{}条记录", logs.size());
            return Result.success(logs);
        } catch (Exception e) {
            logger.error("获取最近操作日志异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 根据IP地址查询操作日志
     * @param ipAddress IP地址
     * @param limit 查询条数限制
     * @return 操作日志列表
     */
    @GetMapping("/by-ip/{ipAddress}")
    @PreAuthorize("hasRole('管理员')")
    public Result<List<OperationLog>> getOperationLogsByIp(
            @PathVariable("ipAddress") String ipAddress,
            @RequestParam(value = "limit", required = false) Integer limit) {

        logger.info("根据IP地址查询操作日志，IP地址：{}，限制条数：{}", ipAddress, limit);

        if (ipAddress == null || ipAddress.trim().isEmpty()) {
            return Result.fail("IP地址无效");
        }

        try {
            List<OperationLog> logs = operationLogService.getOperationLogsByIp(ipAddress, limit);
            logger.info("查询成功，共{}条记录", logs.size());
            return Result.success(logs);
        } catch (Exception e) {
            logger.error("根据IP地址查询操作日志异常：{}", e.getMessage(), e);
            return Result.fail("查询失败：" + e.getMessage());
        }
    }

    /**
     * 检查异常操作
     * @param timeWindow 时间窗口（分钟）
     * @param threshold 阈值
     * @return 异常操作列表
     */
    @GetMapping("/abnormal")
    @PreAuthorize("hasRole('管理员')")
    public Result<List<Map<String, Object>>> checkAbnormalOperations(
            @RequestParam(value = "timeWindow", defaultValue = "60") Integer timeWindow,
            @RequestParam(value = "threshold", defaultValue = "100") Integer threshold) {

        logger.info("检查异常操作，时间窗口：{}分钟，阈值：{}", timeWindow, threshold);

        try {
            List<Map<String, Object>> abnormalOperations = operationLogService.checkAbnormalOperations(timeWindow, threshold);
            logger.info("异常操作检查完成，发现{}个异常", abnormalOperations.size());
            return Result.success(abnormalOperations);
        } catch (Exception e) {
            logger.error("检查异常操作异常：{}", e.getMessage(), e);
            return Result.fail("检查失败：" + e.getMessage());
        }
    }

    /**
     * 获取操作日志统计概览
     * @return 统计概览信息
     */
    @GetMapping("/overview")
    @PreAuthorize("hasAnyRole('管理员', '老师')")
    public Result<Map<String, Object>> getOperationLogOverview() {
        logger.info("获取操作日志统计概览");

        try {
            Map<String, Object> overview = new HashMap<>();

            // 今日操作总数
            LocalDateTime todayStart = LocalDateTime.now().withHour(0).withMinute(0).withSecond(0).withNano(0);
            LocalDateTime todayEnd = todayStart.plusDays(1).minusSeconds(1);
            List<OperationLog> todayLogs = operationLogService.getOperationLogsByTimeRange(todayStart, todayEnd);
            overview.put("todayTotal", todayLogs.size());

            // 今日失败操作数
            long todayFailed = todayLogs.stream().filter(log -> log.getStatus() == 0).count();
            overview.put("todayFailed", todayFailed);

            // 最近7天操作数
            LocalDateTime weekAgo = LocalDateTime.now().minusDays(7);
            Map<String, Long> weekStatistics = operationLogService.countByOperationType(weekAgo, LocalDateTime.now());
            overview.put("weekStatistics", weekStatistics);

            // 最活跃用户
            List<Map<String, Object>> activeUsers = operationLogService.countByUserId(weekAgo, LocalDateTime.now(), 5);
            overview.put("activeUsers", activeUsers);

            logger.info("获取操作日志统计概览成功");
            return Result.success(overview);
        } catch (Exception e) {
            logger.error("获取操作日志统计概览异常：{}", e.getMessage(), e);
            return Result.fail("获取统计概览失败：" + e.getMessage());
        }
    }
}